/*
    libparted - a library for manipulating disk partitions
    Copyright (C) 1999 - 2005 Free Software Foundation, Inc.
        Copyright (C) 2007 Nikhil,Sujay,Nithin,Srivatsa.

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/

/* we need this for O_DIRECT on solaris, it's in the glibc headers */
/* ... and for posix_memalign()       */


#define _GNU_SOURCE

#define PROC_DEVICES_BUFSIZ 16384
#include <sys/types.h>
#include <sys/mkdev.h>
#include "config.h"
#include <sys/dkio.h>
#include <sys/vtoc.h>

#include <parted/parted.h>
#include <parted/debug.h>
#include <parted/solaris.h>
#include<malloc.h>

#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <libgen.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <unistd.h>
#include <dirent.h>

#include <sys/stat.h>
#include <sys/types.h>
#include <sys/utsname.h>        /* for uname() */

#ifdef ENABLE_DEVICE_MAPPER
#include <libdevmapper.h>
#endif

#include "blkpg.h"

#if ENABLE_NLS
#  include <libintl.h>
#  define _(String) dgettext (PACKAGE, String)
#else
#  define _(String) (String)
#endif /* ENABLE_NLS */

//#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))

//#ifndef __NR__llseek
//#define __NR__llseek 140
//#endif

//#ifndef SCSI_IOCTL_SEND_COMMAND
//#define SCSI_IOCTL_SEND_COMMAND 1
//#endif

/* from <solaris/hdreg.h> */
//#define HDIO_GETGEO             0x0301  /* get device geometry */
//#define HDIO_GET_IDENTITY       0x030d  /* get IDE identification info */

#include <parted/vtoc.h>
#include <parted/fdasd.h>

#if defined(O_DIRECT) && (!defined(__s390__) || !defined(__s390x__))
#define RD_MODE (O_RDONLY | O_DIRECT)
#define WR_MODE (O_WRONLY | O_DIRECT)
#define RW_MODE (O_RDWR | O_DIRECT)
#else
#define RD_MODE (O_RDONLY)
#define WR_MODE (O_WRONLY)
#define RW_MODE (O_RDWR)
#endif

struct hd_geometry {
        unsigned char heads;
        unsigned char sectors;
        unsigned short cylinders;
        unsigned long start;
};


/* return device size in bytes (u64 *arg) */
#define BLKGETSIZE64 _IOR(0x12,114,size_t)

struct blkdev_ioctl_param {
        unsigned int block;
        size_t content_length;
        char * block_contents;
};


static char* _device_get_part_path (PedDevice* dev, int num);
static int _partition_is_mounted_by_path (const char* path);


static int
_device_stat (PedDevice* dev, struct stat * dev_stat)
{
        PED_ASSERT (dev != NULL, return 0);
        PED_ASSERT (!dev->external_mode, return 0);

        while (1) {
                if (!stat (dev->path, dev_stat)) {
                        return 1;
                } else {
                        if (ped_exception_throw (
                                PED_EXCEPTION_ERROR,
                                PED_EXCEPTION_RETRY_CANCEL,
                                _("Could not stat device %s - %s."),
                                dev->path,
                                strerror (errno))
                                        != PED_EXCEPTION_RETRY)
                                return 0;
                }
        }
}

static int
_device_probe_type (PedDevice* dev)
{
        struct stat             dev_stat;
        int                     dev_major;
        int                     dev_minor;
        PedExceptionOption      ex_status;

        if (!_device_stat (dev, &dev_stat))
                return 0;

       /* if (!S_ISBLK(dev_stat.st_mode)) {
                dev->type = PED_DEVICE_FILE;
                return 1;
        }*/

        dev_major = major (dev_stat.st_rdev);
        dev_minor = minor (dev_stat.st_rdev);

                dev->type = PED_DEVICE_IDE;
    
        return 1;
}

static void 
_device_set_sector_size (PedDevice* dev)
{
        SolarisSpecific*  arch_specific =SOLARIS_SPECIFIC (dev);
        int sector_size;
        struct vtoc vtoc;
        dev->sector_size = PED_SECTOR_SIZE_DEFAULT;
        dev->phys_sector_size = PED_SECTOR_SIZE_DEFAULT;

        PED_ASSERT (dev->open_count, return);

     
        
        
        if (ioctl (arch_specific->fd, DKIOCGVTOC, &vtoc)) {
                ped_exception_throw (
                        PED_EXCEPTION_WARNING,
                        PED_EXCEPTION_OK,
                        _("Could not determine sector size for %s: %s.\n"
                          "Using the default sector size (%lld)."),
                        dev->path, strerror (errno), PED_SECTOR_SIZE_DEFAULT);
        } else {
                dev->sector_size = (long long)vtoc.v_sectorsz;
                
        }

	//even fdisk does this. Whats the use of the whole function .. dont ask me !! :)
	dev->sector_size = PED_SECTOR_SIZE_DEFAULT;
        
        if (dev->sector_size != PED_SECTOR_SIZE_DEFAULT) {
                ped_exception_throw (
                        PED_EXCEPTION_WARNING,
                        PED_EXCEPTION_OK,
                        _("Device %s has a logical sector size of %lld.  Not "
                          "all parts of GNU Parted support this at the moment, "
                          "and the working code is HIGHLY EXPERIMENTAL.\n"),
                        dev->path, dev->sector_size);
        }
}

static PedSector
_device_get_length (PedDevice* dev)
{
        unsigned long            size;
        SolarisSpecific*          arch_specific = SOLARIS_SPECIFIC (dev);
        uint64_t bytes=0;
	struct dk_minfo dkmi;
	struct dk_geom dk_geom;
	
        PED_ASSERT (dev->open_count > 0, return 0);
        PED_ASSERT (dev->sector_size % 512 == 0, return 0);

       if (ioctl(arch_specific->fd, DKIOCG_PHYGEOM, &dk_geom) < 0) {
                ped_exception_throw (
                        PED_EXCEPTION_BUG,
                        PED_EXCEPTION_CANCEL,
                        _("Unable to determine the size of %s (%s)."),
                        dev->path,
                        strerror (errno));
		
                return 0;
        }
	size = (dk_geom.dkg_ncyl * dk_geom.dkg_nhead * dk_geom.dkg_nsect ) ;

        return size;
}

static int
_device_probe_geometry (PedDevice* dev)
{
        SolarisSpecific*          arch_specific = SOLARIS_SPECIFIC (dev);
        struct stat             dev_stat;
        struct hd_geometry      geometry;
	struct dk_geom dk_geom;
	
        if (!_device_stat (dev, &dev_stat))
                return 0;
	
     //   PED_ASSERT (S_ISBLK (dev_stat.st_mode), return 0);


        _device_set_sector_size (dev);
        
        dev->length = _device_get_length (dev);
        if (!dev->length)
	{
		
                return 0;
	}
	
        dev->bios_geom.sectors = 63;
        dev->bios_geom.heads = 255;
        dev->bios_geom.cylinders
                = dev->length / (63 * 255);
	 if ((ioctl (arch_specific->fd, DKIOCG_PHYGEOM, &dk_geom) >= 0)
                        && dk_geom.dkg_nsect && dk_geom.dkg_nhead) {
                dev->hw_geom.sectors = dk_geom.dkg_nsect;
                dev->hw_geom.heads = dk_geom.dkg_nhead;
                dev->hw_geom.cylinders = dk_geom.dkg_ncyl; 
                                        
	
        } else {
                dev->hw_geom = dev->bios_geom;
        
	
}


        
        return 1;
}

static int
init_ide(PedDevice *dev)
{
	SolarisSpecific*          arch_specific =SOLARIS_SPECIFIC (dev);
        struct stat             dev_stat;
        int                     dev_major;
        
        PedExceptionOption      ex_status;
        char                    hdi_buf[41];
        int                     sector_multiplier = 0;
	
	if (!_device_stat (dev, &dev_stat))
	{
		
                goto error;
	}
	if (!ped_device_open (dev))
	{
		
                goto error;
	}
        if (!_device_probe_geometry (dev))
	{
                
		
		goto error_close_dev;
	}


        ped_device_close (dev);
        return 1;

error_close_dev:
        ped_device_close (dev);
error:
        return 0;
}

static int
init_file (PedDevice* dev)
{
        struct stat     dev_stat;
 
        if (!_device_stat (dev, &dev_stat))
                goto error;
        if (!ped_device_open (dev))
                goto error;

        if (S_ISBLK(dev_stat.st_mode))
                dev->length = _device_get_length (dev);
        else
                dev->length = dev_stat.st_size / 512;
        if (dev->length <= 0) {
                ped_exception_throw (
                        PED_EXCEPTION_ERROR,
                        PED_EXCEPTION_CANCEL,
                        _("The device %s has zero length, and can't possibly "
                          "store a file system or partition table.  Perhaps "
                          "you selected the wrong device?"),
                        dev->path);
                goto error_close_dev;
        }

        ped_device_close (dev);

        dev->bios_geom.cylinders = dev->length / 4 / 32;
        dev->bios_geom.heads = 4;
        dev->bios_geom.sectors = 32;
        dev->hw_geom = dev->bios_geom;
        dev->sector_size = PED_SECTOR_SIZE_DEFAULT;
        dev->phys_sector_size = PED_SECTOR_SIZE_DEFAULT;
        dev->model = strdup ("");
        
        return 1;
        
error_close_dev:
        ped_device_close (dev);
error:
        return 0;
}

static PedDevice*
 solaris_new (const char* path)
{
        PedDevice*      dev=NULL;
	char generic[20] ="Generic Ide";


        PED_ASSERT (path != NULL, return NULL);
	

        dev = (PedDevice*) ped_malloc (sizeof (PedDevice));
        if (!dev)
               goto error;

	
        dev->path =strdup(path);
        if (!dev->path)
	{
		
                goto error_free_dev;
	}
	
	dev->arch_specific
                = (SolarisSpecific*) ped_malloc (sizeof (SolarisSpecific));
        if (!dev->arch_specific)
                goto error_free_path;

        dev->open_count = 0;
        dev->read_only = 0;
        dev->external_mode =0;
        dev->dirty = 0;
        dev->boot_dirty = 0;


	dev->sector_size = 512;
	
	dev->model=strdup(generic);
	dev->phys_sector_size = PED_SECTOR_SIZE_DEFAULT;
	dev->length = 76319;
	dev->bios_geom.sectors = 63;
        dev->bios_geom.heads = 255;
        
        /* no of usable cylinders. */
        
        dev->bios_geom.cylinders= dev->length / (63 * 255);

        
	dev->hw_geom = dev->bios_geom;

	  
        if (!_device_probe_type (dev))
                goto error_free_arch_specific;


        switch (dev->type) {
        case PED_DEVICE_IDE:
                if (!init_ide (dev)){
                	
                        goto error_free_arch_specific;
                      }
                break;

        default:
                ped_exception_throw (PED_EXCEPTION_NO_FEATURE,
                                PED_EXCEPTION_CANCEL,
                                _("ped_device_new()  Unsupported device type"));
                goto error_free_arch_specific;
        }
	
        return dev;

error_free_arch_specific:
        ped_free (dev->arch_specific);
error_free_path:
	
        ped_free (dev->path);
error_free_dev:
        ped_free (dev);
error:
	
        return NULL;
}

static void
solaris_destroy (PedDevice* dev)
{
        ped_free (dev->arch_specific);
        ped_free (dev->path);
        ped_free (dev->model);
        ped_free (dev);
}

static int
solaris_is_busy (PedDevice* dev)
{
        int     i;
        char*   part_name;

        if (_partition_is_mounted_by_path (dev->path))
                return 1;

        for (i = 0; i < 32; i++) {
                int status;

                part_name = _device_get_part_path (dev, i);
                if (!part_name)
                        return 1;
                status = _partition_is_mounted_by_path (part_name);
                ped_free (part_name);

                if (status)
                        return 1;
        }

        return 0;
}


/* we need to flush the master device, and all the partition devices,
 * because there is no coherency between the caches.
 * We should only flush unmounted partition devices, because:
 *  - there is never a need to flush them (we're not doing IO there)
 *  - flushing a device that is mounted causes unnecessary IO, and can
 * even screw journaling & friends up.  Even cause oopsen!
 */
static void
_flush_cache (PedDevice* dev)
{/*yet to be implemented 
        */
}

static int
solaris_open (PedDevice* dev)
{
        SolarisSpecific*  arch_specific = SOLARIS_SPECIFIC (dev);

retry:
        arch_specific->fd = open (dev->path, RW_MODE);

        if (arch_specific->fd == -1) {
                char*   rw_error_msg = strerror (errno);

                arch_specific->fd = open (dev->path, RD_MODE);

                if (arch_specific->fd == -1) {
                        if (ped_exception_throw (
                                PED_EXCEPTION_ERROR,
                                PED_EXCEPTION_RETRY_CANCEL,
                                _("Error opening %s: %s"),
                                dev->path, strerror (errno))
                                        != PED_EXCEPTION_RETRY) {
                                return 0;
                        } else {
                                goto retry;
                        }
                } else {
                        ped_exception_throw (
                                PED_EXCEPTION_WARNING,
                                PED_EXCEPTION_OK,
                                _("Unable to open %s read-write (%s).  %s has "
                                  "been opened read-only."),
                                dev->path, rw_error_msg, dev->path);
                        dev->read_only = 1;
                }
        } else {
                dev->read_only = 0;
        }

       // _flush_cache (dev);

        return 1;
}

static int
solaris_refresh_open (PedDevice* dev)
{
        return 1;
}

static int
solaris_close (PedDevice* dev)
{
        SolarisSpecific*          arch_specific = SOLARIS_SPECIFIC (dev);

        if (dev->dirty)
                _flush_cache (dev);
        close (arch_specific->fd);
        return 1;
}

static int
solaris_refresh_close (PedDevice* dev)
{
        if (dev->dirty)
                _flush_cache (dev);
        return 1;
}

#if SIZEOF_OFF_T < 8

static _syscall5(int,_llseek,
                 unsigned int, fd,
                 unsigned long, offset_high,
                 unsigned long, offset_low,
                 loff_t*, result,
                 unsigned int, origin)

loff_t
llseek (unsigned int fd, loff_t offset, unsigned int whence)
{
        loff_t result;
        int retval;

        retval = _llseek(fd,
                         ((unsigned long long)offset) >> 32,
                         ((unsigned long long)offset) & 0xffffffff,
                         &result,
                         whence);
        return (retval==-1 ? (loff_t) retval : result);
}

#endif /* SIZEOF_OFF_T < 8 */

static int
_device_seek (const PedDevice* dev, PedSector sector)
{
        SolarisSpecific*  arch_specific;
        
        PED_ASSERT (dev->sector_size % 512 == 0, return 0);
        PED_ASSERT (dev != NULL, return 0);
        PED_ASSERT (!dev->external_mode, return 0);
        
        arch_specific =SOLARIS_SPECIFIC (dev);

#if SIZEOF_OFF_T < 8
        if (sizeof (off_t) < 8) {
                loff_t  pos = (loff_t)(sector * dev->sector_size);
                return llseek (arch_specific->fd, pos, SEEK_SET) == pos;
        } else
#endif
        {
                off_t   pos = sector * dev->sector_size;
                return lseek (arch_specific->fd, pos, SEEK_SET) == pos;
        }
}



static int
solaris_read (const PedDevice* dev, void* buffer, PedSector start,
            PedSector count)
{
        SolarisSpecific*          arch_specific = SOLARIS_SPECIFIC (dev);
        int                     status;
        PedExceptionOption      ex_status;
        size_t                  read_length = count * dev->sector_size;
        void*                   diobuf;

        PED_ASSERT (dev->sector_size % 512 == 0, return 0);
	

        while (1) {
                if (_device_seek (dev, start))
                        break;

                ex_status = ped_exception_throw (
                        PED_EXCEPTION_ERROR,
                        PED_EXCEPTION_RETRY_IGNORE_CANCEL,
                        _("%s during seek for read on %s"),
                        strerror (errno), dev->path);

                switch (ex_status) {
                        case PED_EXCEPTION_IGNORE:
                                return 1;

                        case PED_EXCEPTION_RETRY:
                                break;

                        case PED_EXCEPTION_UNHANDLED:
                                ped_exception_catch ();
                        case PED_EXCEPTION_CANCEL:
                                return 0;
                }
        }


      
	diobuf=ped_malloc(count * PED_SECTOR_SIZE_DEFAULT);
	
	diobuf=memalign(512,count * PED_SECTOR_SIZE_DEFAULT);
        while (1) {
                status = read (arch_specific->fd, diobuf, read_length);

                if (status > 0)
                        memcpy(buffer, diobuf, status);
		
                if (status == count * dev->sector_size) break;
                if (status > 0) {
                        read_length -= status;
                        buffer += status;
                        continue;
                }
	
                ex_status = ped_exception_throw (
                        PED_EXCEPTION_ERROR,
                        PED_EXCEPTION_RETRY_IGNORE_CANCEL,
                        _("%s during read on %s"),
                        strerror (errno),
                        dev->path);

                switch (ex_status) {
                        case PED_EXCEPTION_IGNORE:
                                free(diobuf);
                                return 1;

                        case PED_EXCEPTION_RETRY:
                                break;

                        case PED_EXCEPTION_UNHANDLED:
                                ped_exception_catch ();
                        case PED_EXCEPTION_CANCEL:
                                free(diobuf);
                                return 0;
                }
        }
	
        free(diobuf);

        return 1;
}

static int
solaris_write (PedDevice* dev, const void* buffer, PedSector start,
             PedSector count)
{
        SolarisSpecific*          arch_specific = SOLARIS_SPECIFIC (dev);
        int                     status;
        PedExceptionOption      ex_status;
        size_t                  write_length = count * dev->sector_size;
        void*                   diobuf;
        void*                   diobuf_start;



        PED_ASSERT(dev->sector_size % 512 == 0, return 0);

        if (dev->read_only) {
                if (ped_exception_throw (
                        PED_EXCEPTION_ERROR,
                        PED_EXCEPTION_IGNORE_CANCEL,
                        _("Can't write to %s, because it is opened read-only."),
                        dev->path)
                                != PED_EXCEPTION_IGNORE)
                        return 0;
                else
                        return 1;
        }

        while (1) {
                if (_device_seek (dev, start))
                        break;

                ex_status = ped_exception_throw (
                        PED_EXCEPTION_ERROR, PED_EXCEPTION_RETRY_IGNORE_CANCEL,
                        _("%s during seek for write on %s"),
                        strerror (errno), dev->path);

                switch (ex_status) {
                        case PED_EXCEPTION_IGNORE:
                                return 1;

                        case PED_EXCEPTION_RETRY:
                                break;

                        case PED_EXCEPTION_UNHANDLED:
                                ped_exception_catch ();
                        case PED_EXCEPTION_CANCEL:
                                return 0;
                }
        }

#ifdef READ_ONLY
        printf ("ped_device_write (\"%s\", %p, %d, %d)\n",
                dev->path, buffer, (int) start, (int) count);
#else
        dev->dirty = 1;
     
        
        diobuf=ped_malloc(count * PED_SECTOR_SIZE_DEFAULT);
	diobuf=memalign(512,count * PED_SECTOR_SIZE_DEFAULT);    
        
        memcpy(diobuf, buffer, count * PED_SECTOR_SIZE_DEFAULT);
        diobuf_start = diobuf;
        while (1) {
                status = write (arch_specific->fd, diobuf, write_length);
                if (status == count * dev->sector_size) break;
                if (status > 0) {
                        write_length -= status;
                        diobuf += status;
                        continue;
                }

                ex_status = ped_exception_throw (
                        PED_EXCEPTION_ERROR,
                        PED_EXCEPTION_RETRY_IGNORE_CANCEL,
                        _("%s during write on %s"),
                        strerror (errno), dev->path);

                switch (ex_status) {
                        case PED_EXCEPTION_IGNORE:
                                free(diobuf_start);
                                return 1;

                        case PED_EXCEPTION_RETRY:
                                break;

                        case PED_EXCEPTION_UNHANDLED:
                                ped_exception_catch ();
                        case PED_EXCEPTION_CANCEL:
                                free(diobuf_start);
                                return 0;
                }
        }
        free(diobuf_start);
#endif /* !READ_ONLY */
        return 1;
}


/* returns the number of sectors that are ok.
 */
static PedSector
solaris_check (PedDevice* dev, void* buffer, PedSector start, PedSector count)
{
        SolarisSpecific*  arch_specific = SOLARIS_SPECIFIC (dev);
        PedSector       done = 0;
        int             status;
        void*           diobuf;

        PED_ASSERT(dev != NULL, return 0);
        
        if (!_device_seek (dev, start))
                return 0;

        diobuf=ped_malloc(count * PED_SECTOR_SIZE_DEFAULT);
	diobuf=memalign(512,count * PED_SECTOR_SIZE_DEFAULT);    

        for (done = 0; done < count; done += status / dev->sector_size) {
                status = read (arch_specific->fd, diobuf,
                               (size_t) ((count-done) * dev->sector_size));
                if (status > 0)
                        memcpy(buffer, diobuf, status);
                if (status < 0)
                        break;
        }
        free(diobuf);

        return done;
}

static int
_do_fsync (PedDevice* dev)
{
        SolarisSpecific*          arch_specific = SOLARIS_SPECIFIC (dev);
        int                     status;
        PedExceptionOption      ex_status;

        while (1) {
                status = fsync (arch_specific->fd);
                if (status >= 0) break;

                ex_status = ped_exception_throw (
                        PED_EXCEPTION_ERROR,
                        PED_EXCEPTION_RETRY_IGNORE_CANCEL,
                        _("%s during write on %s"),
                        strerror (errno), dev->path);

                switch (ex_status) {
                        case PED_EXCEPTION_IGNORE:
                                return 1;

                        case PED_EXCEPTION_RETRY:
                                break;

                        case PED_EXCEPTION_UNHANDLED:
                                ped_exception_catch ();
                        case PED_EXCEPTION_CANCEL:
                                return 0;
                }
        } 
        return 1;
}

static int
solaris_sync (PedDevice* dev)
{
        PED_ASSERT (dev != NULL, return 0);
        PED_ASSERT (!dev->external_mode, return 0);

        if (dev->read_only)
                return 1;
        if (!_do_fsync (dev))
                return 0;
        _flush_cache (dev);
        return 1;
}

static int
solaris_sync_fast (PedDevice* dev)
{
	PED_ASSERT (dev != NULL, return 0);
        PED_ASSERT (!dev->external_mode, return 0);

        if (dev->read_only)
                return 1;
        if (!_do_fsync (dev))
                return 0;
        /* no cache flush... */
        return 1;
}

static inline int
_compare_digit_state (char ch, int need_digit)
{
        return !!isdigit (ch) == need_digit;
}

struct _entry {
	const char *name;
	size_t len;
};

static void
solaris_probe_all ()
{ 	 
	 DIR            *dir;
	 struct dirent   *dp;
	 char           *path;
         char 		*p1=NULL;
	 char *dev_directory=NULL,*real_path=NULL;
	 int len=0;
	 struct stat        buffer;
	 int n=0;
	 int fp;
	 
	p1=strdup("p0");
	dev_directory=strdup("/dev/rdsk");	
	real_path=(char*)malloc(sizeof(char));	
	
	 dir = opendir("/dev/rdsk");
	 while ((dp = readdir(dir)) != NULL){
    	
        	len=strlen(dp->d_name);
		strcpy(real_path,"");
		len=len-2;
		path=strdup(dp->d_name);
		path=path+len;

		if(!strcmp(path,p1)){
		
				strcat(real_path,dev_directory);			
				strcat(real_path,"/");  			
				strcat(real_path,dp->d_name);

			if(!stat(real_path,&buffer)){
			
				fp=open(real_path,O_RDONLY);
				ioctl(fp,DKIOCREMOVABLE,&n);
				if(!n)
				_ped_device_probe(real_path);
			}
			
			

		}            
    	}
}

static char*
_device_get_part_path (PedDevice* dev, int num)
{
        int             path_len = strlen (dev->path);
        int             result_len = path_len + 16;
        char*           result;

        result = (char*) ped_malloc (result_len);
        if (!result)
                return NULL;

        /* Check for devfs-style /disc => /partN transformation
           unconditionally; the system might be using udev with devfs rules,
           and if not the test is harmless. */
        if (!strcmp (dev->path + path_len - 5, "/disc")) {
                /* replace /disc with /path%d */
                strcpy (result, dev->path);
                snprintf (result + path_len - 5, 16, "/part%d", num);
        } else if (dev->type == PED_DEVICE_DAC960
                        || dev->type == PED_DEVICE_CPQARRAY
                        || dev->type == PED_DEVICE_ATARAID
#ifdef ENABLE_DEVICE_MAPPER
                        || dev->type == PED_DEVICE_DM
#endif
                        || isdigit (dev->path[path_len - 1]))
                snprintf (result, result_len, "%sp%d", dev->path, num);
        else
                snprintf (result, result_len, "%s%d", dev->path, num);

        return result;
}

static char*
solaris_partition_get_path (const PedPartition* part)
{
        return _device_get_part_path (part->disk->dev, part->num);
}

static dev_t
_partition_get_part_dev (const PedPartition* part)
{
        struct stat dev_stat;
        int dev_major, dev_minor;

        if (!_device_stat (part->disk->dev, &dev_stat))
                return (dev_t)0;
        dev_major = major (dev_stat.st_rdev);
        dev_minor = minor (dev_stat.st_rdev);
        return (dev_t)makedev (dev_major, dev_minor + part->num);
}

static int
_mount_table_search (const char* file_name, dev_t dev)
{
        struct stat part_stat;
        char line[512];
        char part_name[512];
        FILE* file;
        int junk;

        file = fopen (file_name, "r");
        if (!file)
                return 0;
        while (fgets (line, 512, file)) {
                junk = sscanf (line, "%s", part_name);
                if (stat (part_name, &part_stat) == 0) {
                        if (part_stat.st_rdev == dev) {
                                fclose (file);
                                return 1;
                        }
                }
        }
        fclose (file);
        return 0;
}

/* mount table search required for os commit. We haven't implemented it yet */

static int
_partition_is_mounted_by_dev (dev_t dev)
{
        return  
                 _mount_table_search( "/etc/mnttab", dev);
}

static int
_partition_is_mounted_by_path (const char *path)
{
        struct stat part_stat;
        if (stat (path, &part_stat) != 0)
                return 0;
        if (!S_ISBLK(part_stat.st_mode))
                return 0;
        return _partition_is_mounted_by_dev (part_stat.st_rdev);
}

static int
_partition_is_mounted (const PedPartition *part)
{
        dev_t dev;
        if (!ped_partition_is_active (part))
                return 0;
        dev = _partition_get_part_dev (part);
        return _partition_is_mounted_by_dev (dev);
}

static int
solaris_partition_is_busy (const PedPartition* part)
{
        PedPartition*   walk;

        PED_ASSERT (part != NULL, return 0);

        if (_partition_is_mounted (part))
                return 1;
        if (part->type == PED_PARTITION_EXTENDED) {
                for (walk = part->part_list; walk; walk = walk->next) {
                        if (solaris_partition_is_busy (walk))
                                return 1;
                }
        }
        return 0;
}




static int
_kernel_reread_part_table (PedDevice* dev)
{/*
        to be implemented
*/
        return 1;
}


static PedDeviceArchOps solaris_dev_ops = {
        _new:           solaris_new,
        destroy:        solaris_destroy,
        is_busy:        solaris_is_busy,
        open:           solaris_open,
        refresh_open:   solaris_refresh_open,
        close:          solaris_close,
        refresh_close:  solaris_refresh_close,
        read:           solaris_read,
        write:          solaris_write,
        check:          solaris_check,
        sync:           solaris_sync,
        sync_fast:      solaris_sync_fast,
        probe_all:      solaris_probe_all
};

PedDiskArchOps solaris_disk_ops =  {
        partition_get_path:     solaris_partition_get_path,
        partition_is_busy:      solaris_partition_is_busy,
       // disk_commit:            solaris_disk_commit
};

PedArchitecture ped_solaris_arch = {
        dev_ops:        &solaris_dev_ops,
        disk_ops:       &solaris_disk_ops
};
